home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-08-22 | 64.3 KB | 2,684 lines |
- This is a new archive version of TRN at patchlevel 3.
- The original posting took up Volume23, issues 60 to 73, with
- various problems. These files replace those issues.
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: respond.c rt-rn.c rt-select.c uudecode.h
- # Wrapped by rsalz@litchi.bbn.com on Fri Aug 23 16:38:57 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 8 (of 14)."'
- if test -f 'respond.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'respond.c'\"
- else
- echo shar: Extracting \"'respond.c'\" \(16294 characters\)
- sed "s/^X//" >'respond.c' <<'END_OF_FILE'
- X/* $Header: respond.c,v 4.3.3.2 91/01/16 03:28:40 davison Trn $
- X *
- X * $Log: respond.c,v $
- X * Revision 4.3.3.2 91/01/16 03:28:40 davison
- X * Integrated rn patches 48-54. Changed fseek to allow for NL_SIZE.
- X *
- X * Revision 4.3.3.1 90/07/21 20:30:18 davison
- X * Initial Trn Release
- X *
- X * Revision 4.3.2.4 90/11/22 16:09:04 sob
- X * Added changes to accomodate pickly C preprocessors
- X *
- X * Revision 4.3.2.3 90/03/22 23:05:19 sob
- X * Fixes provided by Wayne Davison <drivax!davison>
- X *
- X * Revision 4.3.2.2 89/11/26 18:25:10 sob
- X * Enlarged the size of the header buffer to accomodate long references lines.
- X * Fix provided by Joe Buck.
- X *
- X * Revision 4.3.2.1 89/11/06 01:00:26 sob
- X * Added RRN support from NNTP 1.5
- X *
- X * Revision 4.3.1.5 85/09/10 11:05:00 lwall
- X * Improved %m in in_char().
- X *
- X * Revision 4.3.1.4 85/05/23 17:24:49 lwall
- X * Now allows 'r' and 'f' on null articles.
- X *
- X * Revision 4.3.1.3 85/05/15 14:42:32 lwall
- X * Removed duplicate include of intrp.h.
- X *
- X * Revision 4.3.1.2 85/05/14 08:55:15 lwall
- X * Default for normal/mailbox question was applied to wrong buffer.
- X *
- X * Revision 4.3.1.1 85/05/10 11:37:33 lwall
- X * Branch for patches.
- X *
- X * Revision 4.3 85/05/01 11:47:04 lwall
- X * Baseline for release with 4.3bsd.
- X *
- X */
- X
- X#include "EXTERN.h"
- X#include "common.h"
- X#include "intrp.h"
- X#include "head.h"
- X#include "term.h"
- X#include "ng.h"
- X#include "util.h"
- X#include "rn.h"
- X#include "artio.h"
- X#include "final.h"
- X#include "uudecode.h"
- X#include "INTERN.h"
- X#include "respond.h"
- X
- Xstatic char nullart[] = "\nNull article\n";
- X
- Xvoid
- Xrespond_init()
- X{
- X ;
- X}
- X
- Xint
- Xsave_article()
- X{
- X bool use_pref, cut_line();
- X register char *s, *c;
- X char altbuf[CBUFLEN];
- X int iter;
- X bool interactive = (buf[1] == FINISHCMD);
- X char cmd = *buf;
- X
- X if (!finish_command(interactive)) /* get rest of command */
- X return SAVE_ABORT;
- X if ((use_pref = isupper(cmd)) != 0)
- X cmd = tolower(cmd);
- X#ifdef ASYNC_PARSE
- X parse_maybe(art);
- X#endif
- X savefrom = (cmd == 'w' || cmd == 'e' ? htype[PAST_HEADER].ht_minpos : 0);
- X if (artopen(art) == Nullfp) {
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("\n\
- XSaving null articles is not very productive! :-)\n\
- X",stdout) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs(nullart,stdout) FLUSH;
- X#endif
- X return SAVE_DONE;
- X }
- X if (chdir(cwd)) {
- X printf(nocd,cwd) FLUSH;
- X sig_catcher(0);
- X }
- X if (cmd == 'e') { /* is this an extract command? */
- X int cnt = 0;
- X bool found_cut = FALSE;
- X char art_buf[LBUFLEN], *cmdstr;
- X
- X s = buf+1; /* skip e */
- X while (*s == ' ') s++; /* skip leading spaces */
- X safecpy(altbuf,filexp(s),sizeof altbuf);
- X s = altbuf;
- X if (extractprog) {
- X free(extractprog);
- X extractprog = Nullch;
- X }
- X if (*s) {
- X cmdstr = cpytill(buf,s,'|'); /* check for | */
- X s = buf + strlen(buf)-1;
- X while (*s == ' ') s--; /* trim trailing spaces */
- X *++s = '\0';
- X if (*cmdstr) {
- X s = cmdstr+1; /* skip | */
- X while (*s == ' ') s++;
- X if (strEQ(s,"-"))
- X cmdstr = Nullch;
- X else {
- X extractprog = savestr(s); /* put extracter in %e */
- X if (uu_out != Nullfp)
- X uud_end();
- X }
- X } else
- X cmdstr = Nullch;
- X s = buf;
- X } else
- X cmdstr = Nullch;
- X
- X fseek(artfp,savefrom,0);
- X if ((cmd = *s) == '\0')
- X interp(s = buf, (sizeof buf), getval("SAVEDIR",SAVEDIR));
- X if (*s != '/') { /* relative path? */
- X c = (s==buf ? altbuf : buf);
- X sprintf(c, "%s/%s", cwd, s);
- X s = c; /* absolutize it */
- X }
- X if (uu_out != Nullfp) {
- X printf("Continuing %s:%s\n", uu_fname,
- X cmd != '\0' && strNE(savedest,s) ?
- X " (Ignoring conflicting directory)" : nullstr );
- X uudecode(artfp);
- X }
- X else {
- X if (savedest)
- X free(savedest);
- X s = savedest = savestr(s); /* make it handy for %b */
- X if (makedir(s, MD_DIR)) { /* ensure directory exists */
- X int_count++;
- X return SAVE_DONE;
- X }
- X if (chdir(s)) {
- X printf(nocd,s) FLUSH;
- X sig_catcher(0);
- X }
- X s = getwd(buf); /* simplify path for output */
- X while(fgets(art_buf,LBUFLEN,artfp) != Nullch) {
- X if (*art_buf <= ' ')
- X continue; /* Ignore empty or initially-whitespace lines */
- X if (found_cut && cmdstr) {
- X printf("Extracting data into %s using %s:\n",
- X s, extractprog);
- X goto extract_it;
- X }
- X if (((*art_buf == '#' || *art_buf == ':')
- X && (strnEQ(art_buf+1, "! /bin/sh", 9)
- X || strnEQ(art_buf+1, "!/bin/sh", 8)
- X || strnEQ(art_buf+2, "This is ", 8)))
- X || strnEQ(art_buf, "sed ", 4)
- X || strnEQ(art_buf, "cat ", 4)
- X || strnEQ(art_buf, "echo ", 5)) {
- X fseek(artfp,(long)-strlen(art_buf)-NL_SIZE+1,1);
- X savefrom = ftell(artfp);
- X if (cmdstr) {
- X printf("Extracting shar into %s using %s:\n",
- X s, extractprog);
- X goto extract_it;
- X }
- X /* Check for special-case of shar'ed-uuencoded file */
- X while(fgets(art_buf,LBUFLEN,artfp) != Nullch) {
- X if (*art_buf == '#' || *art_buf == ':'
- X || strnEQ(art_buf, "echo ", 5)
- X || strnEQ(art_buf, "sed ", 4))
- X continue;
- X if (strnEQ(art_buf, "Xbegin ", 7))
- X goto uu_decode;
- X break;
- X }
- X printf("Extracting shar into %s:\n", s);
- X extractprog = savestr(filexp(getval("UNSHAR",UNSHAR)));
- X extract_it:
- X cnt = 0;
- X interp(cmd_buf,(sizeof cmd_buf),getval("EXSAVER",EXSAVER));
- X resetty(); /* restore tty state */
- X doshell(SH,cmd_buf);
- X noecho(); /* revert to cbreaking */
- X crmode();
- X break;
- X }
- X else
- X if (!cmdstr
- X && (strnEQ(art_buf,"table ", 6)
- X || strnEQ(art_buf,"table\n", 6)
- X || strnEQ(art_buf,"begin ", 6))) {
- X uu_decode:
- X printf("Extracting uuencoded file into %s:\n", s);
- X extractprog = savestr("-");
- X cnt = 0;
- X fseek(artfp,(long)-strlen(art_buf)-NL_SIZE+1,1);
- X savefrom = ftell(artfp);
- X uud_start(s);
- X uudecode(artfp);
- X break;
- X }
- X else {
- X if (cut_line(art_buf)) {
- X savefrom = ftell(artfp);
- X found_cut = TRUE;
- X }
- X else if (found_cut || ++cnt == 200) {
- X break;
- X }
- X }
- X }/* while */
- X if (cnt) {
- X if (!cmdstr)
- X extractprog = savestr("-");
- X printf("Unable to determine type of file.\n");
- X }
- X }/* if */
- X }
- X else if ((s = index(buf,'|')) != Nullch) {
- X /* is it a pipe command? */
- X s++; /* skip the | */
- X while (*s == ' ') s++;
- X safecpy(altbuf,filexp(s),sizeof altbuf);
- X if (savedest)
- X free(savedest);
- X savedest = savestr(altbuf);
- X interp(cmd_buf, (sizeof cmd_buf), getval("PIPESAVER",PIPESAVER));
- X /* then set up for command */
- X resetty(); /* restore tty state */
- X if (use_pref) /* use preferred shell? */
- X doshell(Nullch,cmd_buf);
- X /* do command with it */
- X else
- X doshell(sh,cmd_buf); /* do command with sh */
- X noecho(); /* and stop echoing */
- X crmode(); /* and start cbreaking */
- X }
- X else { /* normal save */
- X bool there, mailbox;
- X char *savename = getval("SAVENAME",SAVENAME);
- X
- X s = buf+1; /* skip s or S */
- X if (*s == '-') { /* if they are confused, skip - also */
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("Warning: '-' ignored. This isn't readnews.\n",stdout)
- X FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("'-' ignored.\n",stdout) FLUSH;
- X#endif
- X s++;
- X }
- X for (; *s == ' '; s++); /* skip spaces */
- X safecpy(altbuf,filexp(s),sizeof altbuf);
- X s = altbuf;
- X if (! index(s,'/')) {
- X interp(buf, (sizeof buf), getval("SAVEDIR",SAVEDIR));
- X if (makedir(buf,MD_DIR)) /* ensure directory exists */
- X strcpy(buf,cwd);
- X if (*s) {
- X for (c = buf; *c; c++) ;
- X *c++ = '/';
- X strcpy(c,s); /* add filename */
- X }
- X s = buf;
- X }
- X for (iter = 0;
- X (there = stat(s,&filestat) >= 0) &&
- X (filestat.st_mode & S_IFDIR);
- X iter++) { /* is it a directory? */
- X
- X c = (s+strlen(s));
- X *c++ = '/'; /* put a slash before filename */
- X interp(c, s==buf?(sizeof buf):(sizeof altbuf),
- X iter ? "News" : savename );
- X /* generate a default name somehow or other */
- X if (index(c,'/')) { /* yikes, a '/' in the filename */
- X makedir(s,MD_FILE);
- X }
- X }
- X if (*s != '/') { /* relative path? */
- X c = (s==buf ? altbuf : buf);
- X sprintf(c, "%s/%s", cwd, s);
- X s = c; /* absolutize it */
- X }
- X if (savedest)
- X free(savedest);
- X s = savedest = savestr(s); /* doesn't move any more */
- X /* make it handy for %b */
- X if (!there) {
- X if (mbox_always)
- X mailbox = TRUE;
- X else if (norm_always)
- X mailbox = FALSE;
- X else {
- X char *dflt = (instr(savename,"%a") ? "nyq" : "ynq");
- X
- X sprintf(cmd_buf,
- X "\nFile %s doesn't exist--\n use mailbox format? [%s] ",
- X s,dflt);
- X reask_save:
- X in_char(cmd_buf, 'M');
- X putchar('\n') FLUSH;
- X setdef(buf,dflt);
- X#ifdef VERIFY
- X printcmd();
- X#endif
- X if (*buf == 'h') {
- X#ifdef VERBOSE
- X IF(verbose)
- X printf("\n\
- XType y to create %s as a mailbox.\n\
- XType n to create it as a normal file.\n\
- XType q to abort the save.\n\
- X",s) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("\n\
- Xy to create mailbox.\n\
- Xn to create normal file.\n\
- Xq to abort.\n\
- X",stdout) FLUSH;
- X#endif
- X goto reask_save;
- X }
- X else if (*buf == 'n') {
- X mailbox = FALSE;
- X }
- X else if (*buf == 'y') {
- X mailbox = TRUE;
- X }
- X else if (*buf == 'q') {
- X goto s_bomb;
- X }
- X else {
- X fputs(hforhelp,stdout) FLUSH;
- X settle_down();
- X goto reask_save;
- X }
- X }
- X }
- X else if (filestat.st_mode & S_IFCHR)
- X mailbox = FALSE;
- X else {
- X int tmpfd;
- X
- X tmpfd = open(s,0);
- X if (tmpfd == -1)
- X mailbox = FALSE;
- X else {
- X read(tmpfd,buf,LBUFLEN);
- X c = buf;
- X if (!isspace(MBOXCHAR))
- X while (isspace(*c))
- X c++;
- X mailbox = (*c == MBOXCHAR);
- X close(tmpfd);
- X }
- X }
- X
- X safecpy(cmd_buf, filexp(mailbox ?
- X getval("MBOXSAVER",MBOXSAVER) :
- X getval("NORMSAVER",NORMSAVER) ), sizeof cmd_buf);
- X /* format the command */
- X resetty(); /* make terminal behave */
- X if (doshell(use_pref?Nullch:SH,cmd_buf))
- X fputs("Not saved",stdout);
- X else
- X printf("%s to %s %s",
- X there?"Appended":"Saved",
- X mailbox?"mailbox":"file",
- X s);
- X if (interactive)
- X putchar('\n') FLUSH;
- X noecho(); /* make terminal do what we want */
- X crmode();
- X }
- Xs_bomb:
- X#ifdef SERVER
- X if (chdir(spool)) {
- X#else /* not SERVER */
- X if (chdir(spool) || chdir(ngdir)) {
- X#endif /* SERVER */
- X printf(nocd,ngdir) FLUSH;
- X sig_catcher(0);
- X }
- X return SAVE_DONE;
- X}
- X
- Xint
- Xcancel_article()
- X{
- X char *artid_buf;
- X char *ngs_buf;
- X char *from_buf;
- X char *reply_buf;
- X int myuid = getuid();
- X int r = -1;
- X
- X if (artopen(art) == Nullfp) {
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("\n\
- XCancelling null articles is your idea of fun? :-)\n\
- X",stdout) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs(nullart,stdout) FLUSH;
- X#endif
- X return r;
- X }
- X reply_buf = fetchlines(art,REPLY_LINE);
- X from_buf = fetchlines(art,FROM_LINE);
- X artid_buf = fetchlines(art,ARTID_LINE);
- X ngs_buf = fetchlines(art,NGS_LINE);
- X if (!instr(from_buf,sitename) ||
- X (!instr(from_buf,logname) &&
- X !instr(reply_buf,logname) &&
- X#ifdef NEWSADMIN
- X myuid != newsuid &&
- X#endif
- X myuid != ROOTID ) )
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("\nYou can't cancel someone else's article\n",stdout)
- X FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("\nNot your article\n",stdout) FLUSH;
- X#endif
- X else {
- X tmpfp = fopen(headname,"w"); /* open header file */
- X if (tmpfp == Nullfp) {
- X printf(cantcreate,headname) FLUSH;
- X goto no_cancel;
- X }
- X interp(buf, (sizeof buf), getval("CANCELHEADER",CANCELHEADER));
- X fputs(buf,tmpfp);
- X fclose(tmpfp);
- X fputs("\nCanceling...\n",stdout) FLUSH;
- X r = doshell(sh,filexp(getval("CANCEL",CANCEL)));
- X }
- Xno_cancel:
- X free(artid_buf);
- X free(ngs_buf);
- X free(from_buf);
- X free(reply_buf);
- X return r;
- X}
- X
- Xvoid
- Xreply()
- X{
- X bool incl_body = (*buf == 'R');
- X char *maildoer = savestr(filexp(getval("MAILPOSTER",MAILPOSTER)));
- X
- X artopen(art);
- X tmpfp = fopen(headname,"w"); /* open header file */
- X if (tmpfp == Nullfp) {
- X printf(cantcreate,headname) FLUSH;
- X goto no_reply;
- X }
- X interp(buf, (sizeof buf), getval("MAILHEADER",MAILHEADER));
- X fputs(buf,tmpfp);
- X if (!instr(maildoer,"%h"))
- X#ifdef VERBOSE
- X IF(verbose)
- X printf("\n%s\n(Above lines saved in file %s)\n",buf,headname)
- X FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X printf("\n%s\n(Header in %s)\n",buf,headname) FLUSH;
- X#endif
- X if (incl_body && artfp != Nullfp) {
- X interp(buf, (sizeof buf), getval("YOUSAID",YOUSAID));
- X fprintf(tmpfp,"%s\n",buf);
- X#ifdef ASYNC_PARSE
- X parse_maybe(art);
- X#endif
- X fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0);
- X while (fgets(buf,LBUFLEN,artfp) != Nullch) {
- X fprintf(tmpfp,"%s%s",indstr,buf);
- X }
- X fprintf(tmpfp,"\n");
- X }
- X fclose(tmpfp);
- X interp(cmd_buf, (sizeof cmd_buf), maildoer);
- X invoke(cmd_buf,origdir);
- X UNLINK(headname); /* kill the header file */
- Xno_reply:
- X free(maildoer);
- X}
- X
- Xvoid
- Xfollowup()
- X{
- X bool incl_body = (*buf == 'F');
- X char hbuf[4*LBUFLEN]; /* four times the old size */
- X
- X artopen(art);
- X tmpfp = fopen(headname,"w");
- X if (tmpfp == Nullfp) {
- X printf(cantcreate,headname) FLUSH;
- X return;
- X }
- X interp(hbuf, (sizeof hbuf), getval("NEWSHEADER",NEWSHEADER));
- X fprintf(tmpfp,"%s",hbuf);
- X if (incl_body && artfp != Nullfp) {
- X#ifdef VERBOSE
- X if (verbose)
- X fputs("\n\
- X(Be sure to double-check the attribution against the signature, and\n\
- Xtrim the quoted article down as much as possible.)\n\
- X",stdout) FLUSH;
- X#endif
- X interp(buf, (sizeof buf), getval("ATTRIBUTION",ATTRIBUTION));
- X fprintf(tmpfp,"%s\n",buf);
- X#ifdef ASYNC_PARSE
- X parse_maybe(art);
- X#endif
- X fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0);
- X while (fgets(buf,LBUFLEN,artfp) != Nullch) {
- X fprintf(tmpfp,"%s%s",indstr,buf);
- X }
- X fprintf(tmpfp,"\n");
- X }
- X fclose(tmpfp);
- X safecpy(cmd_buf,filexp(getval("NEWSPOSTER",NEWSPOSTER)),sizeof cmd_buf);
- X invoke(cmd_buf,origdir);
- X UNLINK(headname);
- X}
- X
- Xvoid
- Xinvoke(cmd,dir)
- Xchar *cmd,*dir;
- X{
- X if (chdir(dir)) {
- X printf(nocd,dir) FLUSH;
- X return;
- X }
- X#ifdef VERBOSE
- X IF(verbose)
- X printf("\n(leaving cbreak mode; cwd=%s)\nInvoking command: %s\n\n",
- X dir,cmd) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X printf("\n(-cbreak; cwd=%s)\nInvoking: %s\n\n",dir,cmd) FLUSH;
- X#endif
- X resetty(); /* make terminal well-behaved */
- X doshell(sh,cmd); /* do the command */
- X noecho(); /* set no echo */
- X crmode(); /* and cbreak mode */
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs("\n(re-entering cbreak mode)\n",stdout) FLUSH;
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs("\n(+cbreak)\n",stdout) FLUSH;
- X#endif
- X#ifdef SERVER
- X if (chdir(spool)) {
- X#else /* not SERVER */
- X if (chdir(spool) || chdir(ngdir)) {
- X#endif /* SERVER */
- X printf(nocd,ngdir) FLUSH;
- X sig_catcher(0);
- X }
- X}
- X
- X/*
- X** cut_line() determines if a line is meant as a "cut here" marker.
- X** Some examples that we understand:
- X**
- X** BEGIN--cut here--cut here
- X**
- X** ------------------ tear at this line ------------------
- X**
- X** #----cut here-----cut here-----cut here-----cut here----#
- X*/
- Xbool
- Xcut_line(str)
- Xchar *str;
- X{
- X char *cp, got_flag;
- X char word[80];
- X int dash_cnt, equal_cnt;
- X
- X /* Disallow any single-/double-quoted, parenthetical or c-commented
- X ** string lines. Make sure it has the cut-phrase and at least 20
- X ** '-'s or '='s. If only four '-'s are present, check for a duplicate
- X ** of the cut phrase. If we succeed, return TRUE.
- X */
- X for (cp = str, dash_cnt = equal_cnt = 0; *cp; cp++) {
- X switch (*cp) {
- X case '-':
- X dash_cnt++;
- X break;
- X case '=':
- X equal_cnt++;
- X break;
- X case '/':
- X if( *(cp+1) != '*' ) {
- X break;
- X }
- X case '"':
- X case '\'':
- X case '(':
- X case ')':
- X case '[':
- X case ']':
- X case '{':
- X case '}':
- X return FALSE;
- X }
- X }
- X if (dash_cnt < 4 && equal_cnt < 20)
- X return FALSE;
- X
- X got_flag = 0;
- X
- X for (*(cp = word) = '\0'; *str; str++) {
- X if (islower(*str))
- X *cp++ = *str;
- X else if (isupper(*str))
- X *cp++ = tolower(*str);
- X else {
- X if (*word) {
- X *cp = '\0';
- X switch (got_flag) {
- X case 2:
- X if (!strcmp(word, "line")
- X || !strcmp(word, "here"))
- X return TRUE;
- X break;
- X case 1:
- X if (!strcmp(word, "this"))
- X got_flag = 2;
- X if (!strcmp(word, "here")) {
- X if (dash_cnt >= 20 || equal_cnt >= 20)
- X return TRUE;
- X dash_cnt = 20;
- X got_flag = 0;
- X }
- X break;
- X case 0:
- X if (!strcmp( word, "cut")
- X || !strcmp( word, "snip")
- X || !strcmp( word, "tear"))
- X got_flag = 1;
- X break;
- X }
- X *(cp = word) = '\0';
- X }
- X }
- X } /* for *str */
- X
- X return FALSE;
- X}
- END_OF_FILE
- if test 16294 -ne `wc -c <'respond.c'`; then
- echo shar: \"'respond.c'\" unpacked with wrong size!
- fi
- # end of 'respond.c'
- fi
- if test -f 'rt-rn.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rt-rn.c'\"
- else
- echo shar: Extracting \"'rt-rn.c'\" \(21485 characters\)
- sed "s/^X//" >'rt-rn.c' <<'END_OF_FILE'
- X/* $Header: rt-rn.c,v 4.3.3.1 90/07/28 18:07:55 davison Trn $
- X**
- X** $Log: rt-rn.c,v $
- X** Revision 4.3.3.1 90/07/28 18:07:55 davison
- X** Initial Trn Release
- X**
- X*/
- X
- X#include "EXTERN.h"
- X#include "common.h"
- X#include "term.h"
- X#include "final.h"
- X#include "util.h"
- X#include "bits.h"
- X#include "artio.h"
- X#include "ng.h"
- X#include "ngdata.h"
- X#include "search.h"
- X#include "artstate.h"
- X#include "backpage.h"
- X#include "rthreads.h"
- X
- X#ifdef USETHREADS
- X
- Xstatic void find_depth(), cache_tree(), display_tree();
- Xstatic char letter();
- X
- X/* Find the article structure information based on article number.
- X*/
- Xvoid
- Xfind_article( artnum )
- XART_NUM artnum;
- X{
- X register PACKED_ARTICLE *article;
- X register int i;
- X
- X if( !p_articles ) {
- X p_art = Nullart;
- X return;
- X }
- X
- X if( !p_art ) {
- X p_art = p_articles;
- X }
- X /* Start looking for the article num from our last known spot in the array.
- X ** That way, if we already know where we are, we run into ourselves right
- X ** away.
- X */
- X for( article=p_art, i=p_art-p_articles; i < total.article; article++,i++ ) {
- X if( article->num == artnum ) {
- X p_art = article;
- X return;
- X }
- X }
- X /* Didn't find it, so search the ones before our current position.
- X */
- X for( article = p_articles; article != p_art; article++ ) {
- X if( article->num == artnum ) {
- X p_art = article;
- X return;
- X }
- X }
- X p_art = Nullart;
- X}
- X
- Xstatic char tree_indent[] = {
- X ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0,
- X ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', 0
- X};
- X
- Xchar letters[] = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz?";
- X
- Xstatic PACKED_ARTICLE *tree_article;
- X
- Xstatic int max_depth, max_line = -1;
- Xstatic int first_depth, first_line;
- Xstatic int my_depth, my_line;
- Xstatic bool node_on_line;
- Xstatic int node_line_cnt;
- X
- Xstatic int line_num;
- Xstatic int header_indent;
- X
- Xstatic char *tree_lines[11];
- Xstatic char tree_buff[128], *str;
- X
- X/* Prepare tree display for inclusion in the article header.
- X*/
- Xvoid
- Xinit_tree()
- X{
- X register PACKED_ARTICLE *article;
- X
- X#if 000 /* don't do this, since read-status may change */
- X if( curr_p_art == tree_article ) {
- X return;
- X }
- X#endif
- X while( max_line >= 0 ) { /* free any previous tree data */
- X free( tree_lines[max_line--] );
- X }
- X tree_article = curr_p_art;
- X
- X if( !curr_p_art ) {
- X return;
- X }
- X article = p_articles + p_roots[curr_p_art->root].articles;
- X
- X max_depth = max_line = my_depth = my_line = node_line_cnt = 0;
- X find_depth( article, 0 );
- X
- X if( max_depth <= 5 ) {
- X first_depth = 0;
- X } else {
- X if( my_depth+2 > max_depth ) {
- X first_depth = max_depth - 5;
- X } else if( (first_depth = my_depth - 3) < 0 ) {
- X first_depth = 0;
- X }
- X max_depth = first_depth + 5;
- X }
- X if( --max_line < max_tree_lines ) {
- X first_line = 0;
- X } else {
- X if( my_line + max_tree_lines/2 > max_line ) {
- X first_line = max_line - (max_tree_lines-1);
- X } else if( (first_line = my_line - (max_tree_lines-1)/2) < 0 ) {
- X first_line = 0;
- X }
- X max_line = first_line + max_tree_lines-1;
- X }
- X
- X str = tree_buff; /* initialize first line's data */
- X *str++ = ' ';
- X node_on_line = FALSE;
- X line_num = 0;
- X /* cache our portion of the tree */
- X cache_tree( article, 0, tree_indent );
- X
- X max_depth = (max_depth-first_depth) * 5; /* turn depth into char width */
- X max_line -= first_line; /* turn max_line into count */
- X /* shorten tree if lower lines aren't visible */
- X if( node_line_cnt < max_line ) {
- X max_line = node_line_cnt + 1;
- X }
- X}
- X
- X/* A recursive routine to find the maximum tree extents and where we are.
- X*/
- Xstatic void
- Xfind_depth( article, depth )
- XPACKED_ARTICLE *article;
- X{
- X if( depth > max_depth ) {
- X max_depth = depth;
- X }
- X for( ;; ) {
- X if( article == tree_article ) {
- X my_depth = depth;
- X my_line = max_line;
- X }
- X if( article->child_cnt ) {
- X find_depth( article+1, depth+1 );
- X } else {
- X max_line++;
- X }
- X if( !article->siblings ) {
- X break;
- X }
- X article += article->siblings;
- X }
- X}
- X
- X/* Place the tree display in a maximum of 11 lines x 6 nodes.
- X*/
- Xstatic void
- Xcache_tree( article, depth, cp )
- XPACKED_ARTICLE *article;
- Xint depth;
- Xchar *cp;
- X{
- X int depth_mode;
- X
- X cp[1] = ' ';
- X if( depth >= first_depth && depth <= max_depth ) {
- X cp += 5;
- X depth_mode = 1;
- X } else if( depth+1 == first_depth ) {
- X depth_mode = 2;
- X } else {
- X cp = tree_indent;
- X depth_mode = 0;
- X }
- X for( ;; ) {
- X switch( depth_mode ) {
- X case 1: {
- X char ch;
- X
- X *str++ = (article->flags & ROOT_ARTICLE)? ' ' : '-';
- X if( article == tree_article ) {
- X *str++ = '*';
- X }
- X if( was_read( article->num ) ) {
- X *str++ = '(';
- X ch = ')';
- X } else {
- X *str++ = '[';
- X ch = ']';
- X }
- X if( article == recent_p_art && article != tree_article ) {
- X *str++ = '@';
- X }
- X *str++ = letter( article );
- X *str++ = ch;
- X if( article->child_cnt ) {
- X *str++ = (article->child_cnt == 1)? '-' : '+';
- X }
- X if( article->siblings ) {
- X *cp = '|';
- X } else {
- X *cp = ' ';
- X }
- X node_on_line = TRUE;
- X break;
- X }
- X case 2:
- X *tree_buff = (!article->child_cnt)? ' ' :
- X (article->child_cnt == 1)? '-' : '+';
- X break;
- X default:
- X break;
- X }
- X if( article->child_cnt ) {
- X cache_tree( article+1, depth+1, cp );
- X cp[1] = '\0';
- X } else {
- X if( !node_on_line && first_line == line_num ) {
- X first_line++;
- X }
- X if( line_num >= first_line ) {
- X if( str[-1] == ' ' ) {
- X str--;
- X }
- X *str = '\0';
- X tree_lines[line_num-first_line]
- X = safemalloc( str-tree_buff + 1 );
- X strcpy( tree_lines[line_num - first_line], tree_buff );
- X if( node_on_line ) {
- X node_line_cnt = line_num - first_line;
- X }
- X }
- X line_num++;
- X node_on_line = FALSE;
- X }
- X if( !article->siblings || line_num > max_line ) {
- X break;
- X }
- X article += article->siblings;
- X if( !article->siblings ) {
- X *cp = '\\';
- X }
- X if( !first_depth ) {
- X tree_indent[5] = ' ';
- X }
- X strcpy( tree_buff, tree_indent+5 );
- X str = tree_buff + strlen( tree_buff );
- X }
- X}
- X
- X/* Output a header line with possible tree display on the right hand side.
- X** Does automatic wrapping of lines that are too long.
- X*/
- Xint
- Xtree_puts( orig_line, header_line, use_underline )
- Xchar *orig_line;
- XART_LINE header_line;
- Xint use_underline;
- X{
- X char *buf;
- X register char *line, *cp, *end;
- X int pad_cnt, wrap_at;
- X ART_LINE start_line = header_line;
- X int i;
- X char ch;
- X
- X /* Make a modifiable copy of the line */
- X buf = safemalloc( strlen( orig_line ) + 2 ); /* yes, I mean "2" */
- X strcpy( buf, orig_line );
- X line = buf;
- X
- X /* Change any embedded control characters to spaces */
- X for( end = line; *end && *end != '\n'; end++ ) {
- X if( (unsigned char)*end < ' ' ) {
- X *end = ' ';
- X }
- X }
- X *end = '\0';
- X
- X if( !*line ) {
- X strcpy( line, " " );
- X end = line+1;
- X }
- X
- X /* If this is the first subject line, output it with a preceeding [1] */
- X if( use_underline && curr_p_art && (unsigned char)*line > ' ' ) {
- X#ifdef NOFIREWORKS
- X no_sofire();
- X#endif
- X standout();
- X putchar( '[' );
- X putchar( letter( curr_p_art ) );
- X putchar( ']' );
- X un_standout();
- X putchar( ' ' );
- X header_indent = 4;
- X line += 9;
- X i = 0;
- X } else {
- X if( *line != ' ' ) {
- X /* A "normal" header line -- output keyword and set header_indent
- X ** _except_ for the first line, which is a non-standard header.
- X */
- X if( !header_line || !(cp = index( line, ':' )) || *++cp != ' ' ) {
- X header_indent = 0;
- X } else {
- X *cp = '\0';
- X fputs( line, stdout );
- X putchar( ' ' );
- X header_indent = ++cp - line;
- X line = cp;
- X }
- X i = 0;
- X } else {
- X /* Skip whitespace of continuation lines and prepare to indent */
- X while( *++line == ' ' ) {
- X ;
- X }
- X i = header_indent;
- X }
- X }
- X for( ; *line; i = header_indent ) {
- X#ifdef CLEAREOL
- X maybe_eol();
- X#endif
- X if( i ) {
- X putchar( '+' );
- X while( --i ) {
- X putchar( ' ' );
- X }
- X }
- X /* If no (more) tree lines, wrap at COLS-1 */
- X if( max_line < 0 || header_line > max_line+1 ) {
- X wrap_at = COLS-1;
- X } else {
- X wrap_at = COLS - max_depth - 5 - 3;
- X }
- X /* Figure padding between header and tree output, wrapping long lines */
- X pad_cnt = wrap_at - (end - line + header_indent);
- X if( pad_cnt <= 0 ) {
- X cp = line + wrap_at - header_indent - 1;
- X pad_cnt = 1;
- X while( cp > line && *cp != ' ' ) {
- X if( *--cp == ',' || *cp == '.' || *cp == '-' || *cp == '!' ) {
- X cp++;
- X break;
- X }
- X pad_cnt++;
- X }
- X if( cp == line ) {
- X cp += wrap_at - header_indent;
- X pad_cnt = 0;
- X }
- X ch = *cp;
- X *cp = '\0';
- X /* keep rn's backpager happy */
- X vwtary( artline, vrdary( artline - 1 ) );
- X artline++;
- X } else {
- X cp = end;
- X ch = '\0';
- X }
- X if( use_underline ) {
- X underprint( line );
- X } else {
- X fputs( line, stdout );
- X }
- X *cp = ch;
- X /* Skip whitespace in wrapped line */
- X while( *cp == ' ' ) {
- X cp++;
- X }
- X line = cp;
- X /* Check if we've got any tree lines to output */
- X if( wrap_at != COLS-1 && header_line <= max_line ) {
- X char *cp1, *cp2;
- X
- X do {
- X putchar( ' ' );
- X } while( pad_cnt-- );
- X /* Check string for the '*' flagging our current node
- X ** and the '@' flagging our prior node.
- X */
- X cp = tree_lines[header_line];
- X cp1 = index( cp, '*' );
- X cp2 = index( cp, '@' );
- X if( cp1 != Nullch ) {
- X *cp1 = '\0';
- X }
- X if( cp2 != Nullch ) {
- X *cp2 = '\0';
- X }
- X fputs( cp, stdout );
- X /* Handle standout output for '*' and '@' marked nodes, then
- X ** continue with the rest of the line.
- X */
- X while( cp1 || cp2 ) {
- X standout();
- X if( cp1 && (!cp2 || cp1 < cp2) ) {
- X cp = cp1;
- X cp1 = Nullch;
- X *cp++ = '*';
- X putchar( *cp++ );
- X putchar( *cp++ );
- X } else {
- X cp = cp2;
- X cp2 = Nullch;
- X *cp++ = '@';
- X }
- X putchar( *cp++ );
- X un_standout();
- X if( *cp ) {
- X fputs( cp, stdout );
- X }
- X }/* while */
- X }/* if */
- X putchar( '\n' ) FLUSH;
- X header_line++;
- X }/* for remainder of line */
- X
- X /* free allocated copy of line */
- X free( buf );
- X
- X /* return number of lines displayed */
- X return header_line - start_line;
- X}
- X
- X/* Output any parts of the tree that are left to display. Called at the
- X** end of each header.
- X*/
- Xint
- Xfinish_tree( last_line )
- XART_LINE last_line;
- X{
- X ART_LINE start_line = last_line;
- X
- X while( last_line <= max_line ) {
- X artline++;
- X last_line += tree_puts( "+", last_line, 0 );
- X vwtary( artline, artpos ); /* keep rn's backpager happy */
- X }
- X return last_line - start_line;
- X}
- X
- X/* Output the entire article tree for the user.
- X*/
- Xvoid
- Xentire_tree()
- X{
- X int j, root;
- X
- X if( check_page_line() ) {
- X return;
- X }
- X if( !p_art ) {
- X#ifdef VERBOSE
- X IF( verbose )
- X fputs( "\nNo article tree to display.\n", stdout );
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs( "\nNo tree.\n", stdout );
- X#endif
- X } else {
- X root = p_art->root;
- X#ifdef NOFIREWORKS
- X no_sofire();
- X#endif
- X standout();
- X printf( "T%ld:\n", (long)p_roots[root].root_num );
- X un_standout();
- X if( check_page_line() ) {
- X return;
- X }
- X putchar( '\n' );
- X for( j = 0; j < p_roots[root].subject_cnt; j++ ) {
- X sprintf( buf, "[%c] %s\n", letters[j > 9+26+26 ? 9+26+26 : j],
- X subject_ptrs[root_subjects[root]+j] );
- X if( check_page_line() ) {
- X return;
- X }
- X fputs( buf, stdout );
- X }
- X if( check_page_line() ) {
- X return;
- X }
- X putchar( '\n' );
- X if( check_page_line() ) {
- X return;
- X }
- X putchar( ' ' );
- X buf[3] = '\0';
- X display_tree( p_articles+p_roots[p_art->root].articles, tree_indent );
- X
- X if( check_page_line() ) {
- X return;
- X }
- X putchar( '\n' );
- X }
- X}
- X
- X/* A recursive routine to output the entire article tree.
- X*/
- Xstatic void
- Xdisplay_tree( article, cp )
- XPACKED_ARTICLE *article;
- Xchar *cp;
- X{
- X if( cp - tree_indent > COLS || page_line < 0 ) {
- X return;
- X }
- X cp[1] = ' ';
- X cp += 5;
- X for( ;; ) {
- X putchar( (article->flags & ROOT_ARTICLE)? ' ' : '-' );
- X if( was_read( article->num ) ) {
- X buf[0] = '(';
- X buf[2] = ')';
- X } else {
- X buf[0] = '[';
- X buf[2] = ']';
- X }
- X buf[1] = letter( article );
- X if( article == curr_p_art ) {
- X standout();
- X fputs( buf, stdout );
- X un_standout();
- X } else if( article == recent_p_art ) {
- X putchar( buf[0] );
- X standout();
- X putchar( buf[1] );
- X un_standout();
- X putchar( buf[2] );
- X } else {
- X fputs( buf, stdout );
- X }
- X
- X if( article->siblings ) {
- X *cp = '|';
- X } else {
- X *cp = ' ';
- X }
- X if( article->child_cnt ) {
- X putchar( (article->child_cnt == 1)? '-' : '+' );
- X display_tree( article+1, cp );
- X cp[1] = '\0';
- X } else {
- X putchar( '\n' ) FLUSH;
- X }
- X if( !article->siblings ) {
- X break;
- X }
- X article += article->siblings;
- X if( !article->siblings ) {
- X *cp = '\\';
- X }
- X tree_indent[5] = ' ';
- X if( check_page_line() ) {
- X return;
- X }
- X fputs( tree_indent+5, stdout );
- X }
- X}
- X
- Xint
- Xcheck_page_line()
- X{
- X if( page_line < 0 ) {
- X return -1;
- X }
- X if( page_line >= LINES || int_count ) {
- X register int cmd = -1;
- X if( int_count || (cmd = get_anything()) ) {
- X page_line = -1; /* disable further printing */
- X if( cmd > 0 ) {
- X pushchar( cmd );
- X }
- X return cmd;
- X }
- X }
- X page_line++;
- X return 0;
- X}
- X
- X/* Calculate the subject letter representation. "Place-holder" nodes
- X** are marked with a ' ', others get a letter in the sequence:
- X** ' ', '1'-'9', 'A'-'Z', 'a'-'z', '?'
- X*/
- Xstatic char
- Xletter( article )
- XPACKED_ARTICLE *article;
- X{
- X register int subj = article->subject;
- X
- X if( subj < 0 ) {
- X return ' ';
- X }
- X subj -= root_subjects[article->root];
- X if( subj < 9+26+26 ) {
- X return letters[subj];
- X }
- X return '?';
- X}
- X
- X/* Find the first unread article in the (possibly selected) root order.
- X*/
- Xvoid
- Xfirst_art()
- X{
- X register int r;
- X
- X if( !ThreadedGroup ) {
- X art = firstart;
- X return;
- X }
- X p_art = Nullart;
- X art = lastart+1;
- X follow_thread( 'n' );
- X}
- X
- X/* Perform a command over all or a section of the article tree. Most of
- X** the option letters match commands entered from article mode:
- X** n - find the next unread article after current article.
- X** ^N - find the next unread article with the same subject.
- X** N - goto the next article in the thread.
- X** J - junk the entire thread.
- X** k - junk all articles with this same subject.
- X** K - kill all this article's descendants (we know that the caller
- X** killed the current article on the way here).
- X** u - mark entire thread as "unread".
- X** U - mark this article and its descendants as "unread".
- X** f - follow the thread (like 'n'), but don't attempt to find a new thread
- X** if we run off the end.
- X*/
- Xvoid
- Xfollow_thread( cmd )
- Xchar cmd;
- X{
- X int curr_subj = -1, sel;
- X PACKED_ARTICLE *root_limit, *p_art_old = Nullart;
- X bool subthread_flag;
- X
- X reread = FALSE;
- X
- X if( !p_art ) {
- X if( ThreadedGroup && art > lastart ) {
- X p_art = root_limit = p_articles;
- X goto follow_root;
- X }
- X art++;
- X return;
- X }
- X if( cmd == 'k' || cmd == Ctl('n') ) {
- X if( (curr_subj = p_art->subject) == -1) {
- X return;
- X }
- X p_art_old = p_art;
- X }
- X sel = (selected_roots[p_art->root] & 1);
- X if( cmd == 'U' || cmd == 'K' ) {
- X subthread_flag = TRUE;
- X p_art_old = p_art;
- X } else {
- X subthread_flag = FALSE;
- X }
- X /* The current article is already marked as read for 'K' */
- X if( cmd == 'k' || cmd == 'J' || cmd == 'u' ) {
- X p_art = p_articles + p_roots[p_art->root].articles;
- X art = p_art->num;
- X if( cmd == 'u' ) {
- X p_art_old = p_art;
- X cmd = 'U';
- X } else {
- X if( !was_read( art )
- X && (curr_subj < 0 || curr_subj == p_art->subject) ) {
- X set_read( art, sel );
- X }
- X cmd = 'K';
- X }
- X }
- X if( cmd == 'U' ) {
- X if( p_art->subject != -1 ) {
- X set_unread( art, sel );
- X }
- X root_article_cnts[p_art->root] = 1;
- X scan_all_roots = FALSE;
- X }
- X follow_again:
- X sel = (selected_roots[p_art->root] & 1);
- X root_limit = upper_limit( p_art, subthread_flag );
- X for( ;; ) {
- X if( ++p_art == root_limit ) {
- X break;
- X }
- X if( !(art = p_art->num) ) {
- X continue;
- X }
- X if( cmd == 'K' || p_art->subject == -1 ) {
- X if( !was_read( art )
- X && (curr_subj < 0 || curr_subj == p_art->subject) ) {
- X set_read( art, sel );
- X }
- X } else if( cmd == 'U' ) {
- X set_unread( art, sel );
- X } else if( !was_read( art )
- X && (curr_subj < 0 || curr_subj == p_art->subject) ) {
- X return;
- X } else if( cmd == 'N' ) {
- X reread = TRUE;
- X return;
- X }
- X }/* for */
- X if( p_art_old ) {
- X p_art = p_art_old;
- X if( cmd == 'U' && p_art->subject != -1 ) {
- X art = p_art->num;
- X return;
- X }
- X p_art_old = Nullart;
- X cmd = 'n';
- X curr_subj = -1;
- X subthread_flag = FALSE;
- X goto follow_again;
- X }
- X if( cmd == 'f' ) {
- X p_art = Nullart;
- X art = lastart+1;
- X return;
- X }
- X follow_root:
- X if( root_limit != p_articles + total.article ) {
- X register int r;
- X
- X for( r = p_art->root; r < total.root; r++ ) {
- X if( !selected_root_cnt || selected_roots[r] ) {
- X p_art = p_articles + p_roots[r].articles;
- X art = p_art->num;
- X if( p_art->subject == -1 || (cmd != 'N' && was_read( art )) ) {
- X if( cmd != 'N' ) {
- X cmd = 'n';
- X }
- X curr_subj = -1;
- X subthread_flag = FALSE;
- X goto follow_again;
- X }
- X return;
- X }
- X }
- X }
- X if( !count_roots( FALSE ) && unthreaded ) {
- X /* No threaded articles left -- blow everything else away */
- X for( art = firstart; art <= lastart; art++ ) {
- X oneless( art );
- X }
- X unthreaded = 0;
- X }
- X p_art = Nullart;
- X art = lastart+1;
- X}
- X
- X/* Go backward in the article tree. Options match commands in article mode:
- X** p - previous unread article.
- X** ^P - previous unread article with same subject.
- X** P - previous article.
- X*/
- Xvoid
- Xbacktrack_thread( cmd )
- Xchar cmd;
- X{
- X int curr_subj = -1, sel;
- X PACKED_ARTICLE *root_limit, *p_art_old = Nullart;
- X
- X if( art > lastart ) {
- X p_art = p_articles + total.article - 1;
- X root_limit = Nullart;
- X goto backtrack_root;
- X }
- X if( !p_art ) {
- X art--;
- X return;
- X }
- X if( cmd == Ctl('p') ) {
- X if( (curr_subj = p_art->subject) == -1) {
- X return;
- X }
- X p_art_old = p_art;
- X }
- X backtrack_again:
- X sel = (selected_roots[p_art->root] & 1);
- X root_limit = p_articles + p_roots[p_art->root].articles;
- X for( ;; ) {
- X if( p_art-- == root_limit ) {
- X break;
- X }
- X if( !(art = p_art->num) ) {
- X continue;
- X }
- X if( p_art->subject == -1 ) {
- X set_read( art, sel );
- X } else if( !was_read( art )
- X && (curr_subj < 0 || curr_subj == p_art->subject) ) {
- X return;
- X } else if( cmd == 'P' ) {
- X reread = TRUE;
- X return;
- X }
- X }/* for */
- X if( p_art_old ) {
- X p_art = p_art_old;
- X p_art_old = Nullart;
- X curr_subj = -1;
- X goto backtrack_again;
- X }
- X backtrack_root:
- X if( root_limit != p_articles ) {
- X register int r;
- X
- X for( r = p_art->root; r >= 0; r-- ) {
- X if( !selected_root_cnt || selected_roots[r] ) {
- X art = p_art->num;
- X if( cmd != 'P' && was_read( art ) ) {
- X goto backtrack_again;
- X }
- X return;
- X }
- X p_art = p_articles + p_roots[r].articles - 1;
- X }
- X }
- X p_art = Nullart;
- X art = absfirst-1;
- X}
- X
- X/* Find the next root (first if p_art == NULL). If roots are selected,
- X** only choose from selected roots.
- X*/
- Xvoid
- Xnext_root()
- X{
- X register int r;
- X
- X reread = FALSE;
- X
- X if( p_art ) {
- X r = p_art->root+1;
- X } else {
- X r = 0;
- X }
- X for( ; r < total.root; r++ ) {
- X if( !selected_root_cnt || selected_roots[r] ) {
- X try_again:
- X p_art = p_articles + p_roots[r].articles;
- X art = p_art->num;
- X if( p_art->subject == -1 || (!reread && was_read( art )) ) {
- X follow_thread( reread ? 'N' : 'f' );
- X if( art == lastart+1 ) {
- X if( scan_all_roots || selected_root_cnt
- X || root_article_cnts[r] ) {
- X reread = TRUE;
- X goto try_again;
- X }
- X continue;
- X }
- X }
- X return;
- X }
- X }
- X p_art = Nullart;
- X art = lastart+1;
- X forcelast = TRUE;
- X}
- X
- X/* Find previous root (or last if p_art == NULL). If roots are selected,
- X** only choose from selected roots.
- X*/
- Xvoid
- Xprev_root()
- X{
- X register int r;
- X
- X reread = FALSE;
- X
- X if( p_art ) {
- X r = p_art->root - 1;
- X } else {
- X r = total.root - 1;
- X }
- X for( ; r >= 0; r-- ) {
- X if( !selected_root_cnt || selected_roots[r] ) {
- X try_again:
- X p_art = p_articles + p_roots[r].articles;
- X art = p_art->num;
- X if( p_art->subject == -1 || (!reread && was_read( art )) ) {
- X follow_thread( reread ? 'N' : 'f' );
- X if( art == lastart+1 ) {
- X if( scan_all_roots || selected_root_cnt
- X || root_article_cnts[r] ) {
- X reread = TRUE;
- X goto try_again;
- X }
- X continue;
- X }
- X }
- X return;
- X }
- X }
- X p_art = Nullart;
- X art = lastart+1;
- X forcelast = TRUE;
- X}
- X
- X/* Return a pointer value that we will equal when we've reached the end of
- X** the current (sub-)thread.
- X*/
- XPACKED_ARTICLE *
- Xupper_limit( artp, subthread_flag )
- XPACKED_ARTICLE *artp;
- Xbool subthread_flag;
- X{
- X if( subthread_flag ) {
- X for( ;; ) {
- X if( artp->siblings ) {
- X return artp + artp->siblings;
- X }
- X if( !artp->parent ) {
- X break;
- X }
- X artp += artp->parent;
- X }
- X }
- X return p_articles + (artp->root == total.root-1 ?
- X total.article : p_roots[artp->root+1].articles);
- X}
- X
- X#endif /* USETHREADS */
- END_OF_FILE
- if test 21485 -ne `wc -c <'rt-rn.c'`; then
- echo shar: \"'rt-rn.c'\" unpacked with wrong size!
- fi
- # end of 'rt-rn.c'
- fi
- if test -f 'rt-select.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rt-select.c'\"
- else
- echo shar: Extracting \"'rt-select.c'\" \(22344 characters\)
- sed "s/^X//" >'rt-select.c' <<'END_OF_FILE'
- X/* $Header: rt-select.c,v 4.3.3.3 91/01/16 03:28:50 davison Trn $
- X**
- X** $Log: rt-select.c,v $
- X** Revision 4.3.3.3 91/01/16 03:28:50 davison
- X** Changed %d --> %ld.
- X** Changed some expressions to registers to bypass a compiler problem.
- X**
- X** Revision 4.3.3.2 90/08/20 18:32:33 davison
- X** Reset scan_all_roots while selecting.
- X**
- X** Revision 4.3.3.1 90/07/24 22:04:07 davison
- X** Initial Trn Release
- X**
- X*/
- X
- X#include "EXTERN.h"
- X#include "common.h"
- X#include "rn.h"
- X#include "rcstuff.h"
- X#include "term.h"
- X#include "final.h"
- X#include "util.h"
- X#include "help.h"
- X#include "bits.h"
- X#include "artsrch.h"
- X#include "ng.h"
- X#include "ngstuff.h"
- X#include "rthreads.h"
- X
- X#ifdef USETHREADS
- X
- Xstatic int count_subj_lines();
- Xstatic void display_subj();
- X
- X/* When display mode is 'l', each author gets a separate line; when 'm', up to
- X** three authors share a line; when 's', no authors are displayed.
- X*/
- Xstatic char *display_mode = select_order;
- Xstatic ART_NUM article_count;
- Xstatic int author_line;
- Xstatic char first_two_chars[3] = { ' ', ' ', '\0' }, mask = 1;
- X
- X#define MAX_SEL 64
- X
- X/* Display a menu of roots for the user to choose from. If cmd is '+'
- X** we display all the unread roots and allow the user to mark roots as
- X** selected and perform various commands upon the articles. If cmd is
- X** 'U' we display all the previously read roots and allow the user to
- X** select which ones should be marked as unread.
- X*/
- Xchar
- Xselect_thread( cmd )
- Xchar cmd;
- X{
- X register int i, j, cnt;
- X ART_NUM art_hold = art;
- X int line_cnt, screen_line, subj_line_cnt;
- X int cur_root, page_root, last_root = -1;
- X ART_LINE running_total, last_running;
- X int last_line, got_dash;
- X int max_root;
- X int first, last;
- X int root_line[MAX_SEL], root_hold[MAX_SEL];
- X int ch, action;
- X char page_char, end_char;
- X char promptbuf[80];
- X bool etc, clean_screen, empty_ok, displayed_status;
- X char oldmode = mode;
- X#ifndef CONDSUB
- X char tmpbuf[2];
- X#endif
- X char *select_chars, *in_select;
- X int max_cnt;
- X
- X mode = 't';
- X unread_selector = (cmd == 'U');
- X clear_on_stop = TRUE;
- X empty_ok = FALSE;
- X
- X select_threads:
- X /* Setup for selecting articles to read or set unread */
- X scan_all_roots = FALSE;
- X if( unread_selector ) {
- X page_char = '>';
- X end_char = 'Z';
- X page_root = 0;
- X last_root = -1;
- X cmd = 0;
- X } else {
- X page_char = page_select;
- X end_char = end_select;
- X page_root = select_page;
- X if( curr_p_art ) {
- X last_root = curr_p_art->root;
- X }
- X }
- X mask = unread_selector+1;
- X
- X /* Leave empty roots selected for a short time to give them a chance
- X ** to 'q' out of the selector if they got here by mistake.
- X */
- X max_root = count_roots( FALSE );
- X
- X /* If nothing to display, we're done. */
- X if( !article_count && !empty_ok ) {
- X all_empty:
- X clear_on_stop = FALSE;
- X mode = oldmode;
- X putchar( '\n' );
- X if( unread_selector ) {
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs( "\nNo articles to set unread.\n", stdout );
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs( "\nNo articles.\n", stdout ) FLUSH;
- X#endif
- X unread_selector = 0;
- X mask = 1;
- X } else {
- X#ifdef VERBOSE
- X IF(verbose)
- X fputs( "\nNo unread articles to select.\n", stdout );
- X ELSE
- X#endif
- X#ifdef TERSE
- X fputs( "\nNo articles.\n", stdout ); /* let "them" FLUSH */
- X#endif
- X }
- X (void) count_roots( TRUE );
- X art = art_hold;
- X p_art = curr_p_art;
- X return 'q';
- X }
- X if( unread_selector ) {
- X for( j = 0; j < total.root; j++ ) {
- X selected_roots[j] |= 4;
- X }
- X }
- X if( page_root >= max_root ) {
- X ch = '<';
- X } else {
- X ch = '>';
- X }
- X cur_root = 0;
- X running_total = 0;
- X for( i = 0; i < page_root; i++ ) {
- X running_total += root_article_cnts[i];
- X }
- X do {
- X select_chars = getval( "SELECTCHARS", SELECTCHARS );
- X max_cnt = strlen( select_chars );
- X if( max_cnt > MAX_SEL ) {
- X max_cnt = MAX_SEL;
- X }
- X if( ch == '<' && i ) {
- X screen_line = 2;
- X cnt = 0;
- X /* Scan the roots in reverse to go back a page */
- X do {
- X if( !root_article_cnts[--i] ) {
- X continue;
- X }
- X first = root_subjects[i];
- X last = first + p_roots[i].subject_cnt;
- X line_cnt = 0;
- X for( j = first; j < last; j++ ) {
- X line_cnt += count_subj_lines( i, j );
- X }
- X if( line_cnt > LINES - 5 ) {
- X line_cnt = LINES - 5;
- X }
- X screen_line += line_cnt;
- X if( screen_line > LINES - 3 ) {
- X i++;
- X break;
- X }
- X running_total -= root_article_cnts[i];
- X cnt++;
- X } while( i > 0 && cnt < max_cnt );
- X }
- X
- X /* Present a page of subjects to the user */
- X#ifndef CLEAREOL
- X clear();
- X#else
- X if( can_home_clear ) {
- X home_cursor();
- X maybe_eol();
- X } else {
- X clear();
- X }
- X#endif
- X carriage_return();
- X page_root = i;
- X last_running = running_total;
- X#ifdef NOFIREWORKS
- X no_sofire();
- X#endif
- X standout();
- X fputs( ngname, stdout );
- X un_standout();
- X printf( "\t\t\t\t%ld %sarticle%s\n", (long)article_count,
- X unread_selector? "read " : nullstr,
- X article_count == 1 ? nullstr : "s" );
- X#ifdef CLEAREOL
- X maybe_eol();
- X#endif
- X putchar( '\n' ) FLUSH;
- X screen_line = 2;
- X for( cnt = 0; i < max_root && cnt < max_cnt; i++ ) {
- X if( last_root == i ) {
- X cur_root = cnt;
- X }
- X /* Check each root for articles to list */
- X if( !root_article_cnts[i] ) {
- X continue;
- X }
- X first = root_subjects[i];
- X last = first + p_roots[i].subject_cnt;
- X
- X /* Compute how many lines we need to display the subjects/authors */
- X etc = FALSE;
- X line_cnt = 0;
- X for( j = first; j < last; j++ ) {
- X subj_line_cnt = count_subj_lines( i, j );
- X line_cnt += subj_line_cnt;
- X /* If this root is too long to fit on the screen all by
- X ** itself, trim it to fit and set the "etc" flag.
- X */
- X if( line_cnt > LINES - 5 ) {
- X last = j;
- X line_cnt -= subj_line_cnt;
- X if( line_cnt != LINES - 5 ) {
- X last++;
- X line_cnt = LINES - 5;
- X }
- X if( screen_line == 2 ) {
- X etc = TRUE;
- X }
- X break;
- X }
- X }
- X /* If it doesn't fit, save it for the next page */
- X if( screen_line + line_cnt > LINES - 3 ) {
- X break;
- X }
- X /* Output the subjects, with optional authors */
- X root_line[cnt] = screen_line;
- X running_total += root_article_cnts[i];
- X first_two_chars[0] = select_chars[cnt];
- X first_two_chars[1] = (selected_roots[i] & 4) ? '-' :
- X (selected_roots[i] & mask) ? '+' : ' ';
- X author_line = screen_line;
- X for( j = first; j < last; j++ ) {
- X display_subj( i, j );
- X }
- X screen_line += line_cnt;
- X root_hold[cnt++] = i;
- X if( etc ) {
- X fputs( " ...etc.", stdout );
- X i++;
- X break;
- X }
- X }/* for */
- X last_root = -1;
- X if( cur_root && cur_root >= cnt ) {
- X cur_root = cnt - 1;
- X }
- X
- X /* Check if there is really anything left to display. */
- X if( !running_total && !empty_ok ) {
- X goto all_empty;
- X }
- X empty_ok = FALSE;
- X
- X last_line = screen_line+1;
- X#ifdef CLEAREOL
- X maybe_eol();
- X#endif
- X putchar( '\n' ) FLUSH;
- X /* Prompt the user */
- X strcpy( promptbuf, "-- Select threads -- " );
- X if( i != max_root ) {
- X sprintf( promptbuf+21, "%s%ld%% [%c%c] --",
- X (!page_root? "Top " : nullstr),
- X (long)(running_total*100 / article_count),
- X page_char, end_char );
- X } else {
- X sprintf( promptbuf+21, "%s [%c%c] --",
- X (!page_root? "All" : "Bot"), end_char, page_char );
- X }
- X if( cur_root > cnt ) {
- X cur_root = 0;
- X }
- X screen_line = root_line[cur_root];
- X#ifdef CLEAREOL
- X if( erase_screen && can_home_clear ) {
- X clear_rest();
- X }
- X#endif
- X displayed_status = FALSE;
- X prompt_select:
- X standout();
- X fputs( promptbuf, stdout );
- X un_standout();
- X if( can_home ) {
- X carriage_return();
- X goto_line( last_line, screen_line );
- X }
- X got_dash = 0;
- X /* Grab some commands from the user */
- X for( ;; ) {
- X fflush(stdout);
- X eat_typeahead();
- X#ifdef CONDSUB
- X getcmd( buf );
- X ch = *buf;
- X#else
- X getcmd( tmpbuf ); /* If no conditionals, don't allow macros */
- X ch = *tmpbuf;
- X buf[0] = ch;
- X buf[1] = FINISHCMD;
- X#endif
- X in_select = index( select_chars, ch );
- X /* Plaster any inherited empty roots on first command, if not q. */
- X if( cmd && (in_select || (ch != '\033' && ch != 'q')) ) {
- X max_root = count_roots( TRUE );
- X cmd = 0;
- X }
- X if( displayed_status && can_home ) {
- X goto_line( screen_line, last_line+1 );
- X erase_eol();
- X screen_line = last_line+1;
- X displayed_status = FALSE;
- X }
- X if( ch == '-' ) {
- X got_dash = 1;
- X if( !can_home ) {
- X putchar( '-' );
- X fflush( stdout );
- X }
- X continue;
- X }
- X if( ch == ' ' ) {
- X if( i == max_root ) {
- X ch = end_char;
- X } else {
- X ch = page_char;
- X }
- X }
- X if( !in_select && (index( "<>^$!?&:/hDJLNqQUXZ\n\r\t\033", ch )
- X || ch == Ctl('l') || ch == Ctl('r') || ch == Ctl('k')) ) {
- X break;
- X }
- X if( in_select ) {
- X j = in_select - select_chars;
- X if( j >= cnt ) {
- X dingaling();
- X j = -1;
- X } else if( got_dash ) {
- X ;
- X } else if( selected_roots[root_hold[j]] & mask ) {
- X action = (unread_selector ? 'k' : '-');
- X } else {
- X action = '+';
- X }
- X } else if( ch == 'y' || ch == '.' ) {
- X j = cur_root;
- X if( selected_roots[root_hold[j]] & mask ) {
- X action = (unread_selector ? 'k' : '-');
- X } else {
- X action = '+';
- X }
- X } else if( ch == 'k' || ch == 'j' || ch == ',' ) {
- X j = cur_root;
- X action = 'k';
- X } else if( ch == 'm' || ch == '\\' ) {
- X j = cur_root;
- X action = 'm';
- X } else if( ch == '@' ) {
- X cur_root = 0;
- X j = cnt-1;
- X got_dash = 1;
- X action = '@';
- X } else if( ch == '[' || ch == 'p' ) {
- X if( --cur_root < 0 ) {
- X cur_root = cnt ? cnt-1 : 0;
- X }
- X j = -1;
- X } else if( ch == ']' || ch == 'n' ) {
- X if( ++cur_root >= cnt ) {
- X cur_root = 0;
- X }
- X j = -1;
- X } else {
- X if( can_home ) {
- X goto_line( screen_line, last_line+1 );
- X screen_line = last_line+1;
- X } else {
- X putchar( '\n' );
- X }
- X printf( "Type ? for help." );
- X settle_down();
- X displayed_status = TRUE;
- X
- X if( can_home ) {
- X carriage_return();
- X } else {
- X putchar( '\n' );
- X }
- X j = -1;
- X }
- X if( j >= 0 ) {
- X if( !got_dash ) {
- X cur_root = j;
- X } else {
- X got_dash = 0;
- X if( j < cur_root ) {
- X ch = cur_root-1;
- X cur_root = j;
- X j = ch;
- X }
- X }
- X if( ++j == cnt ) {
- X j = 0;
- X }
- X do {
- X register int r;
- X register char maskr = mask;
- X r = root_hold[cur_root];
- X if( can_home ) {
- X goto_line( screen_line, root_line[cur_root] );
- X screen_line = root_line[cur_root];
- X }
- X putchar( select_chars[cur_root] );
- X if( action == '@' ) {
- X if( selected_roots[r] & 4 ) {
- X ch = (unread_selector ? '+' : ' ');
- X } else if( unread_selector ) {
- X ch = 'k';
- X } else
- X if( selected_roots[r] & maskr ) {
- X ch = '-';
- X } else {
- X ch = '+';
- X }
- X } else {
- X ch = action;
- X }
- X switch( ch ) {
- X case '+':
- X if( !(selected_roots[r] & maskr) ) {
- X selected_roots[r] |= maskr;
- X selected_root_cnt++;
- X selected_count += root_article_cnts[r];
- X putchar( '+' );
- X }
- X /* FALL THROUGH */
- X case 'm':
- X if( selected_roots[r] & 4 ) {
- X selected_roots[r] &= ~4;
- X if( ch == 'm' ) {
- X putchar( ' ' );
- X }
- X } else if( ch == 'm' ) {
- X goto unsel;
- X }
- X break;
- X case 'k':
- X if( !(selected_roots[r] & 4) ) {
- X selected_roots[r] |= 4;
- X putchar( '-' );
- X }
- X /* FALL THROUGH */
- X case '-':
- X unsel:
- X if( selected_roots[r] & maskr ) {
- X selected_roots[r] &= ~maskr;
- X selected_root_cnt--;
- X selected_count -= root_article_cnts[r];
- X if( ch != 'k' ) {
- X putchar( ' ' );
- X }
- X }
- X break;
- X }
- X fflush( stdout );
- X if( ++cur_root == cnt ) {
- X cur_root = 0;
- X }
- X if( can_home ) {
- X carriage_return();
- X }
- X } while( cur_root != j );
- X } else {
- X got_dash = FALSE;
- X }
- X if( can_home ) {
- X goto_line( screen_line, root_line[cur_root] );
- X screen_line = root_line[cur_root];
- X }
- X }/* for */
- X if( can_home) {
- X goto_line( screen_line, last_line );
- X }
- X clean_screen = TRUE;
- X do_command:
- X if( ch == 'L' ) {
- X if( !*++display_mode ) {
- X display_mode = select_order;
- X }
- X ch = Ctl('l');
- X cur_root = 0;
- X } else if( ch == '$' ) {
- X ch = '<';
- X page_root = max_root;
- X last_running = article_count;
- X cur_root = 0;
- X } else if( ch == '^' || ch == Ctl('r') ) {
- X ch = '>';
- X i = 0;
- X running_total = 0;
- X cur_root = 0;
- X } else if( ch == 'h' || ch == '?' ) {
- X putchar( '\n' );
- X if( (ch = help_select()) || (ch = pause_getcmd()) ) {
- X goto got_cmd;
- X }
- X ch = Ctl('l');
- X } else if( index( ":/&!", ch ) ) {
- X erase_eol(); /* erase the prompt */
- X if( !finish_command( TRUE ) ) { /* get rest of command */
- X if( clean_screen ) {
- X screen_line = root_line[cur_root];
- X goto prompt_select;
- X }
- X goto extend_done;
- X }
- X if( ch == '&' || ch == '!' ) {
- X one_command = TRUE;
- X perform( buf, FALSE );
- X one_command = FALSE;
- X
- X putchar( '\n' ) FLUSH;
- X clean_screen = FALSE;
- X } else {
- X int selected_save = selected_root_cnt;
- X
- X if( ch == ':' ) {
- X clean_screen = (use_selected() == 2) && clean_screen;
- X } else {
- X /* Force the search to begin at absfirst or firstart,
- X ** depending upon whether they specified the 'r' option.
- X */
- X art = lastart+1;
- X page_line = 1;
- X switch( art_search( buf, sizeof buf, FALSE ) ) {
- X case SRCH_ERROR:
- X case SRCH_ABORT:
- X case SRCH_INTR:
- X fputs( "\nInterrupted\n", stdout ) FLUSH;
- X break;
- X case SRCH_DONE:
- X case SRCH_SUBJDONE:
- X fputs( "Done\n", stdout ) FLUSH;
- X break;
- X case SRCH_NOTFOUND:
- X fputs( "\nNot found.\n", stdout ) FLUSH;
- X break;
- X case SRCH_FOUND:
- X break;
- X }
- X clean_screen = FALSE;
- X }
- X /* Recount, in case something has changed. */
- X max_root = count_roots( !unread_selector );
- X
- X if( (selected_save -= selected_root_cnt) != 0 ) {
- X putchar( '\n' );
- X if( selected_save < 0 ) {
- X fputs( "S", stdout );
- X selected_save *= -1;
- X } else {
- X fputs( "Des", stdout );
- X }
- X printf( "elected %d thread%s.", selected_save,
- X selected_save == 1 ? nullstr : "s" );
- X clean_screen = FALSE;
- X }
- X if( !clean_screen ) {
- X putchar('\n') FLUSH;
- X }
- X }/* if !& or :/ */
- X
- X if( clean_screen ) {
- X carriage_return();
- X up_line();
- X erase_eol();
- X screen_line = root_line[cur_root];
- X goto prompt_select;
- X }
- X extend_done:
- X if( (ch = pause_getcmd()) ) {
- X got_cmd:
- X if( ch > 0 ) {
- X /* try to optimize the screen update for some commands. */
- X if( !index( select_chars, ch )
- X && (index( "<>^$!?&:/hDJLNqQUXZ\n\r\t\033", ch )
- X || ch == Ctl('k')) ) {
- X buf[0] = ch;
- X buf[1] = FINISHCMD;
- X goto do_command;
- X }
- X pushchar( ch | 0200 );
- X }
- X }
- X ch = Ctl('l');
- X } else if( ch == Ctl('k') ) {
- X edit_kfile();
- X ch = Ctl('l');
- X } else if( !unread_selector && (ch == 'X' || ch == 'D' || ch == 'J') ) {
- X if( ch == 'D' ) {
- X j = page_root;
- X last = i;
- X } else {
- X j = 0;
- X last = max_root;
- X }
- X for( ; j < last; j++ ) {
- X if( (!(selected_roots[j] & 1) ^ (ch == 'J'))
- X && (cnt = root_article_cnts[j]) ) {
- X p_art = p_articles + p_roots[j].articles;
- X art = 0;
- X follow_thread( 'J' );
- X }
- X }
- X max_root = count_roots( TRUE );
- X if( article_count
- X && (ch == 'J' || (ch == 'D' && !selected_root_cnt)) ) {
- X ch = Ctl('l');
- X cur_root = 0;
- X } else {
- X break;
- X }
- X } else if( ch == 'J' ) {
- X for( j = 0; j < max_root; j++ ) {
- X selected_roots[j] = (selected_roots[j] & ~2) | 4;
- X }
- X selected_root_cnt = selected_count = 0;
- X ch = Ctl('l');
- X }
- X if( ch == '>' ) {
- X cur_root = 0;
- X } else if( ch == '<' || (page_root && page_root >= max_root) ) {
- X cur_root = 0;
- X running_total = last_running;
- X if( !(i = page_root) || !max_root ) {
- X ch = '>';
- X } else {
- X ch = '<';
- X }
- X } else if( ch == Ctl('l') ) {
- X i = page_root;
- X running_total = last_running;
- X ch = '>';
- X } else if( ch == '\r' || ch == '\n' ) {
- X if( !selected_root_cnt ) {
- X register r = root_hold[cur_root];
- X selected_roots[r] = mask;
- X selected_root_cnt++;
- X selected_count += root_article_cnts[r];
- X }
- X }
- X } while( (ch == '>' && i < max_root) || ch == '<' );
- X putchar( '\n' ) FLUSH;
- X
- X if( unread_selector ) {
- X /* Turn selections into unread selected roots. Let count_roots()
- X ** fix the counts after we're through.
- X */
- X last_root = -1;
- X for( j = 0; j < total.root; j++ ) {
- X if( !(selected_roots[j] & 4) ) {
- X if( selected_roots[j] & 2 ) {
- X selected_roots[j] = 1;
- X }
- X p_art = p_articles + p_roots[j].articles;
- X art = 0;
- X follow_thread( 'u' );
- X } else {
- X selected_roots[j] &= ~4;
- X }
- X }
- X } else {
- X select_page = page_root;
- X for( j = 0; j < total.root; j++ ) {
- X if( selected_roots[j] & 4 ) {
- X selected_roots[j] = 0;
- X p_art = p_articles + p_roots[j].articles;
- X art = 0;
- X follow_thread( 'J' );
- X }
- X }
- X }
- X if( ch == 'U' ) {
- X unread_selector = !unread_selector;
- X empty_ok = TRUE;
- X goto select_threads;
- X }
- X
- X if( unread_selector ) {
- X unread_selector = 0;
- X mask = 1;
- X (void) count_roots( FALSE );
- X }
- X if( ch == '\033' || Ctl(ch) == Ctl('q') ) {
- X ch = (ch == 'Q' ? 'Q' : 'q');
- X art = art_hold;
- X p_art = curr_p_art;
- X } else if( ch == 'N' ) {
- X art = art_hold;
- X p_art = curr_p_art;
- X } else {
- X first_art();
- X }
- X clear_on_stop = FALSE;
- X mode = oldmode;
- X return ch;
- X}
- X
- Xstatic int author_cnt, first_author;
- X
- X/* Counts the number of lines needed to output a subject, including optional
- X** authors.
- X*/
- Xstatic int
- Xcount_subj_lines( root, subj )
- Xint root;
- Xint subj;
- X{
- X PACKED_ARTICLE *artp, *root_limit;
- X int author_subj;
- X
- X author_cnt = 0;
- X author_subj = subj;
- X first_author = -1;
- X
- X if( !subject_cnts[subj] ) {
- X return 0;
- X }
- X if( *display_mode == 's' ) { /* no-author mode takes one line */
- X return ++author_cnt;
- X }
- X bzero( author_cnts, total.author * sizeof (WORD) );
- X
- X /* Count authors associated with this subject. Increments author_cnts. */
- X artp = p_articles + p_roots[root].articles;
- X root_limit = upper_limit( artp, FALSE );
- X for( ; artp != root_limit; artp++ ) {
- X if( artp->subject == author_subj
- X && (!was_read( artp->num ) ^ unread_selector) ) {
- X if( artp->author < 0 || artp->author >= total.author ) {
- X printf( "\
- XFound invalid author (%d) with valid subject (%d)! [%ld]\n",
- X artp->author, artp->subject, artp->num );
- X artp->author = 0;
- X } else {
- X if( first_author < 0 ) {
- X first_author = artp->author;
- X }
- X if( !author_cnts[artp->author]++ ) {
- X author_cnt++;
- X }
- X }
- X }
- X }
- X
- X if( *display_mode == 'm' ) {
- X return (author_cnt+4)/3;
- X } else {
- X return author_cnt;
- X }
- X}
- X
- Xstatic void
- Xdisplay_subj( root, subj )
- Xint root;
- Xint subj;
- X{
- X PACKED_ARTICLE *artp, *root_limit;
- X char *str;
- X
- X count_subj_lines( root, subj );
- X if( !author_cnt ) {
- X return;
- X }
- X artp = p_articles + p_roots[root].articles;
- X if( artp->subject != -1 && (artp->flags & ROOT_ARTICLE)
- X && (!was_read(artp->num) ^ unread_selector) ) {
- X str = nullstr;
- X } else {
- X str = ">";
- X }
- X#ifdef CLEAREOL
- X maybe_eol();
- X#endif
- X if( *display_mode == 's' ) {
- X printf( "%s%3d %s%.71s\n", first_two_chars,
- X subject_cnts[subj], str, subject_ptrs[subj] ) FLUSH;
- X } else {
- X printf( "%s%-16.16s%3d %s%.55s", first_two_chars,
- X author_ptrs[first_author],
- X subject_cnts[subj], str, subject_ptrs[subj] );
- X if( author_cnt > 1 ) {
- X author_cnts[first_author] = 0;
- X author_cnt = 0;
- X root_limit = upper_limit( artp, FALSE );
- X for( ; artp != root_limit; artp++ ) {
- X if( artp->author >= 0 && author_cnts[artp->author] ) {
- X switch( author_cnt % 3 ) {
- X case 0:
- X putchar( '\n' ) FLUSH;
- X if( ++author_line >= LINES - 3 ) {
- X return;
- X }
- X#ifdef CLEAREOL
- X maybe_eol();
- X#endif
- X putchar( ' ' );
- X putchar( ' ' );
- X break;
- X case 1:
- X putchar( '\t' );
- X putchar( '\t' );
- X break;
- X case 2:
- X putchar( '\t' );
- X break;
- X }
- X author_cnt += (*display_mode == 'm');
- X printf( "%-16.16s", author_ptrs[artp->author] );
- X author_cnts[artp->author] = 0;
- X }/* if */
- X }/* for */
- X }/* if */
- X putchar( '\n' ) FLUSH;
- X author_line++;
- X }/* if */
- X first_two_chars[0] = first_two_chars[1] = ' ';
- X}
- X
- X/* Get each root's article count, and subject count(s); count total
- X** articles and selected articles (use unread_selector to determine
- X** whether to count read or unread articles); deselect any roots we
- X** find that are empty (if do_unselect is TRUE); find the last non-
- X** empty root, and return its count (the index+1).
- X*/
- Xint
- Xcount_roots( do_unselect )
- Xbool do_unselect;
- X{
- X register int count;
- X register PACKED_ARTICLE *artp, *root_limit, *art_limit;
- X int last_root = -1;
- X
- X article_count = selected_count = selected_root_cnt = 0;
- X
- X if( !(artp = p_articles) ) {
- X return 0;
- X }
- X art_limit = artp + total.article;
- X root_limit = upper_limit( artp, 0 );
- X
- X bzero( subject_cnts, total.subject * sizeof (WORD) );
- X count = 0;
- X
- X for( ;; ) {
- X if( artp->subject == -1 ) {
- X if( !was_read( artp->num ) ) {
- X oneless( artp->num );
- X }
- X } else if( (!was_read( artp->num ) ^ unread_selector) ) {
- X count++;
- X subject_cnts[artp->subject]++;
- X }
- X if( ++artp == root_limit ) {
- X register int root_num = artp[-1].root;
- X register char maskr = mask;
- X
- X root_article_cnts[root_num] = count;
- X if( count ) {
- X article_count += count;
- X if( selected_roots[root_num] & maskr ) {
- X selected_roots[root_num] &= ~4;
- X selected_root_cnt++;
- X selected_count += count;
- X }
- X last_root = root_num;
- X } else if( do_unselect ) {
- X selected_roots[root_num] &= ~maskr;
- X } else if( selected_roots[root_num] & maskr ) {
- X selected_roots[root_num] &= ~4;
- X selected_root_cnt++;
- X }
- X if( artp == art_limit ) {
- X break;
- X }
- X root_limit = upper_limit( artp, 0 );
- X count = 0;
- X }
- X }
- X if( do_unselect ) {
- X scan_all_roots = !article_count;
- X }
- X unthreaded = toread[ng] - article_count;
- X
- X return last_root+1;
- X}
- X
- X/* Count the unread articles attached to the given root number.
- X*/
- Xint
- Xcount_one_root( root_num )
- Xint root_num;
- X{
- X int last = (root_num == total.root-1 ? total.article
- X : p_roots[root_num+1].articles);
- X register int count = 0, i;
- X
- X for( i = p_roots[root_num].articles; i < last; i++ ) {
- X if( p_articles[i].subject != -1 && !was_read( p_articles[i].num ) ) {
- X count++;
- X }
- X }
- X root_article_cnts[root_num] = count;
- X
- X return count;
- X}
- X
- X#endif /* USETHREADS */
- END_OF_FILE
- if test 22344 -ne `wc -c <'rt-select.c'`; then
- echo shar: \"'rt-select.c'\" unpacked with wrong size!
- fi
- # end of 'rt-select.c'
- fi
- if test -f 'uudecode.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'uudecode.h'\"
- else
- echo shar: Extracting \"'uudecode.h'\" \(404 characters\)
- sed "s/^X//" >'uudecode.h' <<'END_OF_FILE'
- X/* $Header: uudecode.h,v 4.3.3.2 91/01/16 03:41:53 davison Trn $
- X**
- X** $Log: uudecode.h,v $
- X** Revision 4.3.3.2 91/01/16 03:41:53 davison
- X** Added optional prototyping.
- X**
- X** Revision 4.3.3.1 90/06/20 22:49:08 davison
- X** Initial Trn Release
- X**
- X*/
- X
- XEXT FILE *uu_out INIT(NULL);
- XEXT char uu_fname[MAXFILENAME];
- X
- Xint uud_start ANSI((char *));
- Xint uud_send ANSI((void));
- Xint uudecode ANSI((FILE *));
- END_OF_FILE
- if test 404 -ne `wc -c <'uudecode.h'`; then
- echo shar: \"'uudecode.h'\" unpacked with wrong size!
- fi
- # end of 'uudecode.h'
- fi
- echo shar: End of archive 8 \(of 14\).
- cp /dev/null ark8isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 14 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
-